<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app"></div>
<script>
    // 渲染器
    function createRenderer(options = {}) {
        const {
            createElement,
            setElementText,
            insert
        } = options

        // 挂载函数
        function mountElement(vnode, container) {
            const el = createElement(vnode.type)
            // 设置vnode属性
            if (vnode.props) {
                for (const propsKey in vnode.props) {
                    el[propsKey] = vnode.props[propsKey]
                    // 或者用setAttribute
                    // el.setAttribute(propsKey, vnode.props[propsKey])
                }
            }
            if (typeof vnode.children === 'string') {
                // 如果节点值是string，设置文本
                setElementText(el, vnode.children)
            }else if (Array.isArray(vnode.children)) {
                // children是一个数组，遍历这个数组，数组每个元素都是一个vnode
                // 调用patch将他们挂载上去. oldVNode=null, container = el
                vnode.children.forEach(child => {
                    patch(null, child, el)
                })
            }
            // 将el挂载在container上
            insert(el, container)
        }

        // 补丁函数
        function patch(oldVNode, newVNode, container) {
            if (!oldVNode) {
                // 挂载
                mountElement(newVNode, container)
            } else {
                // 打补丁
            }
        }

        // 渲染函数
        function render(vnode, container) {
            if (vnode) {
                // 新vnode存在，将其与旧vnode一起传递给patch函数打补丁
                patch(container._vnode, vnode, container)
            } else {
                if (container._vnode) {
                    // 新vnode不存在，旧vnode存在，说明是卸载(unmount)操作
                    // 清空DOM
                    container.innerHTML = ''
                }
            }
            container._vnode = vnode // vnode改成旧的
        }

        // 同构渲染
        function hydrate(vnode, container) {

        }

        return {
            render,
            hydrate
        }
    }

    const vnode = {
        type: 'div',
        props: {
          id: 'foo'
        },
        children: [
            {
                type: 'h1',
                children: 'hello h1'
            }
        ]
    }
    const browserOption = {
        createElement(tag) {
            return document.createElement(tag)
        },
        setElementText(el, text) {
            el.textContent = text
        },
        insert(el, parent, anchor = null) {
            parent.insertBefore(el, anchor)
        }
    }
    const renderer = createRenderer(browserOption)
    renderer.render(vnode, document.getElementById('app'))

    // 自定义渲染器
    const printOption = {
        createElement(tag) {
            console.log(`创建元素${tag}`)
            return {tag}
        },
        setElementText(el, text) {
            console.log(`设置 ${JSON.stringify(el)} 的文本内容为： ${text}`)
            el.text = text
        },
        insert(el, parent, anchor) {
            console.log(`将 ${JSON.stringify(el)} 添加到 ${JSON.stringify(parent)} 下`)
            parent.children = el
        }
    }
    const rendererPrint = createRenderer(printOption)
    // const container = {type: 'root'}
    rendererPrint.render(vnode, {type: 'root'})
</script>
</body>
</html>
